﻿using System;
using System.Collections.Generic;
using System.Data.Linq; 
using System.Linq;
using System.Text;
using System.Linq.Expressions; 
using System.Reflection;
using System.Data;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace YXQ.Common.Extension
{
    public static class EntityExtension
    {

        public static int Delete<T>(this ObjectContext obj, int id) where T : class
        {
            //return  obj.DeleteObject(T);
            return 1;
        }



        /// <summary>
        /// 当空时则new一个新对象作为默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entityObj"></param>
        /// <returns></returns>
        public static T ToOriginalOrDefault<T>(this T entityObj)
            where T : EntityObject, new()
        {
            if (entityObj == null)
                return new T();
            else
            {
                return entityObj;
            }
        }



        //public static  IEnumerator<int> GetEnumerator()
        //{
        //    while (true)
        //    {
        //        yield return Environment.TickCount;
        //    }
        //}
        //System.Collections.IEnumerator  System.Collections.IEnumerable.GetEnumerator()
        //{
        //    return GetEnumerator();
        //}


        /// <summary>
        /// 与dto按属性名匹配
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dto"></param>
        /// <param name="entity"></param>
        public static void MapToEntity<T>(this object dto, T entity)
        {
            MapToEntity(dto, entity, false);
        }
        /// <summary>
        /// not contains 查询不包含
        /// </summary>
        /// <typeparam name="TElement"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="valueSelector"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static Expression<Func<TElement, bool>> NotContains<TElement, TValue>(
    Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {

            if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }

            if (null == values) { throw new ArgumentNullException("values"); }

            ParameterExpression p = valueSelector.Parameters.Single();

            // p => valueSelector(p) == values[0] || valueSelector(p) == ...

            if (!values.Any())
            {
                return e => true;
            }

            var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));

            var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
            body = Expression.Not(body);
            return Expression.Lambda<Func<TElement, bool>>(body, p);

        }
        //测试方法
        //class Program
        //{
        //    static void Main(string[] args)
        //    {
        //        List<int> fullList = new List<int>();
        //        for (int i = 0; i < 20; i++)
        //        {
        //            fullList.Add(i);
        //        }

        //        List<int> filter = new List<int>();
        //        filter.Add(2);
        //        filter.Add(5);
        //        filter.Add(10);

        //        List<int> results = fullList.AsQueryable().ExtWhereIn<int, int>(item => item, filter).ToList();
        //        foreach (int result in results)
        //        {
        //            Console.WriteLine(result);
        //        }
        //    }
        //}    

        //扩展方法2
        //List<Product> GetProducts(List<int> productIds)
        //{
        //    using (MyEntities context = new MyEntities())
        //    {
        //        return context.Products.ExtWhereIn<Product, int>(product => product.Id, productIds).ToList();
        //    }
        //} 




        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T">table</typeparam>
        /// <typeparam name="TValue">type</typeparam>
        /// <param name="query">IQueryable</param>
        /// <param name="valueSelector"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static IQueryable<T> ExtWhereIn<T, TValue>(this ObjectQuery<T> query, Expression<Func<T, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            return query.Where(BuildContainsExpression<T, TValue>(valueSelector, values));
        }
        public static IQueryable<T> ExtWhereIn<T, TValue>(this IQueryable<T> query, Expression<Func<T, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            return query.Where(BuildContainsExpression<T, TValue>(valueSelector, values));
        }
        private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(
            Expression<Func<TElement, TValue>> valueSelector,
            IEnumerable<TValue> values)
        {
            if (null == valueSelector)
            {
                throw new ArgumentNullException("valueSelector");
            }
            if (null == values)
            {
                throw new ArgumentNullException("values");
            }
            ParameterExpression p = valueSelector.Parameters.Single();
            //p => valueSelector(p) == values[0] || valueSelector(p) == ...            
            if (!values.Any())
            {
                return e => false;
            }
            var equals =
                values.Select(
                    value =>
                    (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }



        /// <summary>
        /// contains查询包含
        /// </summary>
        /// <typeparam name="TElement">表名</typeparam>
        /// <typeparam name="TValue">类型</typeparam>
        /// <param name="valueSelector"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static Expression<Func<TElement, bool>> Contains<TElement, TValue>(
                Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {

            if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }
            if (null == values) { throw new ArgumentNullException("values"); }
            ParameterExpression p = valueSelector.Parameters.Single();
            if (!values.Any())
            {
                return e => false;
            }

            var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }

      

        /// <summary>
        /// 与dto按属性名匹配
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dto"></param>
        /// <param name="entity"></param>
        public static void MapToEntity<T>(this object dto, T entity, bool isDefaultEmpty)
        {
            Type entityType = entity.GetType();
            Type dtoType = dto.GetType();
            PropertyInfo[] entityPropertyInfos = entityType.GetProperties();
            PropertyInfo[] dtoPropertyInfos = dtoType.GetProperties();

            var dtoProps = new Dictionary<string, PropertyInfo>();
            foreach (var item in dtoPropertyInfos)
            {
                dtoProps[item.Name] = item;
            }


            foreach (var p in entityPropertyInfos)
            {
                if (dtoProps.ContainsKey(p.Name))
                {
                    object data = dtoProps[p.Name].GetValue(dto, null);
                    string dataString = data != null ? data.ToString() : string.Empty;
                    object trueData = data;

                    if (p.PropertyType == typeof(bool?))
                    {
                        continue;
                    }
                    else if (p.PropertyType == typeof(int?))
                    {
                        if (dataString.ToLower() == "true")
                            trueData = 1;
                        else if (dataString.ToLower() == "false")
                            trueData = null;
                        else if (dataString.ToLower().Trim() == string.Empty)
                            trueData = null;
                    }
                    else if (p.PropertyType == typeof(string))
                    {
                        if (isDefaultEmpty && trueData == null)
                        {
                            trueData = string.Empty;
                        }
                    }
                    p.SetValue(entity, trueData.ChangeType(p.PropertyType), null);
                }
            }
        }

        /// <summary>
        /// 从DataTable里读取数据将数据转换成实例
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="reader">DataReader</param>
        /// <returns>实例</returns>
        public static T ToEntity<T>(this DataTable dt)
        {
            return GetEntityFromDataTable<T>(dt);
        }
        /// <summary>
        /// 从DataTable里读取数据将数据转换成实例
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="reader">DataReader</param>
        /// <returns>实例</returns>
        public static T GetEntityFromDataTable<T>(DataTable dt)
        {
            Type type = typeof(T);

            object t = Activator.CreateInstance(type);


            string tempName = "";

            foreach (DataRow dr in dt.Rows)
            {


                // 获得此模型的公共属性
                PropertyInfo[] propertys = typeof(T).GetProperties();

                foreach (PropertyInfo pi in propertys)
                {
                    tempName = pi.Name;

                    // 检查DataTable是否包含此列
                    if (dt.Columns.Contains(tempName))
                    {
                        // 判断此属性是否有Setter
                        if (!pi.CanWrite) continue;
                        if (dr[tempName] != DBNull.Value)
                        {

                            if (pi.PropertyType.ToString() == "System.String" || pi.PropertyType.ToString() == "System.Nullable`1[System.String]")
                                if (dr[tempName] != null)
                                {
                                    pi.SetValue(t, Convert.ToString(dr[tempName]), null);
                                }
                                else
                                {
                                    pi.SetValue(t, null, null);
                                }

                            if (pi.PropertyType.ToString() == "System.Boolean" || pi.PropertyType.ToString() == "System.Nullable`1[System.Boolean]")
                                if (dr[tempName] != null)
                                {
                                    pi.SetValue(t, Convert.ToBoolean(dr[tempName]), null);
                                }
                                else
                                {
                                    pi.SetValue(t, null, null);
                                }

                            if (pi.PropertyType.ToString() == "System.Int32" || pi.PropertyType.ToString() == "System.Nullable`1[System.Int32]")
                                if (dr[tempName] != null)
                                {
                                    pi.SetValue(t, Convert.ToInt32(dr[tempName]), null);
                                }
                                else
                                {
                                    pi.SetValue(t, null, null);
                                }

                            if (pi.PropertyType.ToString() == "System.DateTime" || pi.PropertyType.ToString() == "System.Nullable`1[System.DateTime]")
                                if (dr[tempName] != null)
                                {
                                    pi.SetValue(t, Convert.ToDateTime(dr[tempName]), null);
                                }
                                else
                                {
                                    pi.SetValue(t, null, null);
                                }

                        }
                    }
                }


            }

            return (T)t;


        }

    }
}
